/*
 ------------------------------------------------------------------------------
 Copyright (C) 2013 Eternal Games.

 This file is part of the GLQuake source code.

 The GLQuake source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The GLQuake source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the GLQuake source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// msgSystem.h - framework used by dynamic-link libraries
//


#ifndef __FRAMEWORK_MSGSYSTEM_H__
#define __FRAMEWORK_MSGSYSTEM_H__


/*
 ==============================================================================

 Message I/O:

 No memory is allocated, so the data buffer set with Init must be in static
 memory. If dynamically allocated memory is used, it should not be freed until
 all message I/O is completed.

 Byte ordering and alignment is handled automatically.

 It is safe to write to and read from a message buffer at the same time.

 ==============================================================================
*/

#define MAX_MSG_SIZE				8192		// Max size of a message

struct msg_t {
	byte *					data;
	int						size;
	int						bits;

	bool					allowOverflow;		// If false, throw an error when overflowed
	bool					overflowed;			// Set to true when overflowed

	int						writeCount;			// Number of bits written so far
	int						writeBytes;			// Number of bytes written so far
	int						writeBit;			// Current bit in last written byte

	int						readCount;			// Number of bits read so far
	int						readBytes;			// Number of bytes read so far
	int						readBit;			// Current bit in last read byte
};

// Functions exported by the engine
struct glqMsgSystem_t {
	// Initializes a message buffer for writing and/or reading
	void					(*Init)(msg_t *msg, byte *data, int size, bool allowOverflow);

	// Writing functions
	int						(*GetWriteState)(msg_t *msg);
	void					(*SetWriteState)(msg_t *msg, int bits);
	void					(*ClearWriteState)(msg_t *msg);

	int						(*RemainingWriteBits)(msg_t *msg);
	int						(*RemainingWriteBytes)(msg_t *msg);

	void					(*WriteAlign)(msg_t *msg);

	void					(*WriteBits)(msg_t *msg, int value, int bits);
	void					(*WriteBool)(msg_t *msg, bool value);
	void					(*WriteChar)(msg_t *msg, int value);
	void					(*WriteByte)(msg_t *msg, int value);
	void					(*WriteShort)(msg_t *msg, int value);
	void					(*WriteWord)(msg_t *msg, int value);
	void					(*WriteLong)(msg_t *msg, int value);
	void					(*WriteHalf)(msg_t *msg, float value);
	void					(*WriteFloat)(msg_t *msg, float value);
	void					(*WriteAngle)(msg_t *msg, float angle);
	void					(*WriteAngle8)(msg_t *msg, float angle);
	void					(*WriteAngle16)(msg_t *msg, float angle);
	void					(*WriteAngles)(msg_t *msg, const glqAngles &angles);
	void					(*WriteAngles8)(msg_t *msg, const glqAngles &angles);
	void					(*WriteAngles16)(msg_t *msg, const glqAngles &angles);
	void					(*WriteVec2)(msg_t *msg, const glqVec2 &vec);
	void					(*WriteVec3)(msg_t *msg, const glqVec3 &vec);
	void					(*WriteVec4)(msg_t *msg, const glqVec4 &vec);
	void					(*WriteVec5)(msg_t *msg, const glqVec5 &vec);
	void					(*WriteNormal)(msg_t *msg, const glqVec3 &normal);
	void					(*WriteString)(msg_t *msg, const char *string);
	void					(*WriteData)(msg_t *msg, const void *data, int size);

	void					(*WriteDeltaBits)(msg_t *msg, int oldValue, int newValue, int bits);
	void					(*WriteDeltaChar)(msg_t *msg, int oldValue, int newValue);
	void					(*WriteDeltaByte)(msg_t *msg, int oldValue, int newValue);
	void					(*WriteDeltaShort)(msg_t *msg, int oldValue, int newValue);
	void					(*WriteDeltaWord)(msg_t *msg, int oldValue, int newValue);
	void					(*WriteDeltaLong)(msg_t *msg, int oldValue, int newValue);
	void					(*WriteDeltaHalf)(msg_t *msg, float oldValue, float newValue);
	void					(*WriteDeltaFloat)(msg_t *msg, float oldValue, float newValue);
	void					(*WriteDeltaAngle)(msg_t *msg, float oldAngle, float newAngle);
	void					(*WriteDeltaAngle8)(msg_t *msg, float oldAngle, float newAngle);
	void					(*WriteDeltaAngle16)(msg_t *msg, float oldAngle, float newAngle);
	void					(*WriteDeltaAngles)(msg_t *msg, const glqAngles &oldAngles, const glqAngles &newAngles);
	void					(*WriteDeltaAngles8)(msg_t *msg, const glqAngles &oldAngles, const glqAngles &newAngles);
	void					(*WriteDeltaAngles16)(msg_t *msg, const glqAngles &oldAngles, const glqAngles &newAngles);
	void					(*WriteDeltaVec2)(msg_t *msg, const glqVec2 &oldVec, const glqVec2 &newVec);
	void					(*WriteDeltaVec3)(msg_t *msg, const glqVec3 &oldVec, const glqVec3 &newVec);
	void					(*WriteDeltaVec4)(msg_t *msg, const glqVec4 &oldVec, const glqVec4 &newVec);
	void					(*WriteDeltaVec5)(msg_t *msg, const glqVec5 &oldVec, const glqVec5 &newVec);
	void					(*WriteDeltaNormal)(msg_t *msg, const glqVec3 &oldNormal, const glqVec3 &newNormal);

	// Reading functions
	int						(*GetReadState)(msg_t *msg);
	void					(*SetReadState)(msg_t *msg, int bits);
	void					(*ClearReadState)(msg_t *msg);

	int						(*RemainingReadBits)(msg_t *msg);
	int						(*RemainingReadBytes)(msg_t *msg);

	void					(*ReadAlign)(msg_t *msg);

	int						(*ReadBits)(msg_t *msg, int bits);
	bool					(*ReadBool)(msg_t *msg);
	int						(*ReadChar)(msg_t *msg);
	int						(*ReadByte)(msg_t *msg);
	int						(*ReadShort)(msg_t *msg);
	int						(*ReadWord)(msg_t *msg);
	int						(*ReadLong)(msg_t *msg);
	float					(*ReadHalf)(msg_t *msg);
	float					(*ReadFloat)(msg_t *msg);
	float					(*ReadAngle)(msg_t *msg);
	float					(*ReadAngle8)(msg_t *msg);
	float					(*ReadAngle16)(msg_t *msg);
	glqAngles				(*ReadAngles)(msg_t *msg);
	glqAngles				(*ReadAngles8)(msg_t *msg);
	glqAngles				(*ReadAngles16)(msg_t *msg);
	glqVec2					(*ReadVec2)(msg_t *msg);
	glqVec3					(*ReadVec3)(msg_t *msg);
	glqVec4					(*ReadVec4)(msg_t *msg);
	glqVec5					(*ReadVec5)(msg_t *msg);
	glqVec3					(*ReadNormal)(msg_t *msg);
	int						(*ReadString)(msg_t *msg, char *string, int maxLength);
	int						(*ReadData)(msg_t *msg, void *data, int size);

	int						(*ReadDeltaBits)(msg_t *msg, int oldValue, int bits);
	int						(*ReadDeltaChar)(msg_t *msg, int oldValue);
	int						(*ReadDeltaByte)(msg_t *msg, int oldValue);
	int						(*ReadDeltaShort)(msg_t *msg, int oldValue);
	int						(*ReadDeltaWord)(msg_t *msg, int oldValue);
	int						(*ReadDeltaLong)(msg_t *msg, int oldValue);
	float					(*ReadDeltaHalf)(msg_t *msg, float oldValue);
	float					(*ReadDeltaFloat)(msg_t *msg, float oldValue);
	float					(*ReadDeltaAngle)(msg_t *msg, float oldAngle);
	float					(*ReadDeltaAngle8)(msg_t *msg, float oldAngle);
	float					(*ReadDeltaAngle16)(msg_t *msg, float oldAngle);
	glqAngles				(*ReadDeltaAngles)(msg_t *msg, const glqAngles &oldAngles);
	glqAngles				(*ReadDeltaAngles8)(msg_t *msg, const glqAngles &oldAngles);
	glqAngles				(*ReadDeltaAngles16)(msg_t *msg, const glqAngles &oldAngles);
	glqVec2					(*ReadDeltaVec2)(msg_t *msg, const glqVec2 &oldVec);
	glqVec3					(*ReadDeltaVec3)(msg_t *msg, const glqVec3 &oldVec);
	glqVec4					(*ReadDeltaVec4)(msg_t *msg, const glqVec4 &oldVec);
	glqVec5					(*ReadDeltaVec5)(msg_t *msg, const glqVec5 &oldVec);
	glqVec3					(*ReadDeltaNormal)(msg_t *msg, const glqVec3 &oldNormal);
};


#endif	// __FRAMEWORK_MSGSYSTEM_H__